home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / MNetsrc.hqx / Mac TCP_IP Source v.33 / nrcmd.c < prev    next >
Text File  |  1989-02-27  |  26KB  |  1,246 lines

  1. /* net/rom user command processing
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "global.h"
  8. #include "config.h"
  9. #include "mbuf.h"
  10. #include "ax25.h"
  11. #include "timer.h"
  12. #include "iface.h"
  13. #include "lapb.h"
  14. #include "netrom.h"
  15. #include "nr4.h"
  16. #include "ax_mbx.h"
  17. #include "cmdparse.h"
  18. #include "session.h"
  19. #include <ctype.h>
  20.  
  21. #undef NRDEBUG
  22.  
  23. char *Nr4states[] = {
  24.     "Disconnected",
  25.     "Conn Pending",
  26.     "Connected",
  27.     "Disc Pending"
  28. } ;
  29.  
  30. char *Nr4reasons[] = {
  31.     "Normal",
  32.     "By Peer",
  33.     "Timeout",
  34.     "Reset",
  35.     "Refused"
  36. } ;
  37.  
  38. static int dointerface(), dobcnodes(), donodetimer(), donrroute(),
  39.            donrttl(), doobsotimer(), donodefilter(), donrverbose(),
  40.            donrconnect(), donrreset(), donrwindow(), donrirtt(),
  41.            donracktime(), donrqlimit(), donrchoketime(), donrretries(),
  42.            donrstatus(), donrkick() ;
  43.  
  44. static struct cmds nrcmds[] = {
  45.     "acktime",    donracktime,    0,    NULLCHAR,    NULLCHAR,
  46.     "bcnodes",    dobcnodes,    2,    "netrom bcnodes <interface>", NULLCHAR,
  47.     
  48. /* Put connect before choketime to make it the default expansion of 'c' */
  49.  
  50.     "connect",    donrconnect,2,    "netrom connect <node>",    NULLCHAR,
  51.     "choketime",    donrchoketime,    0,    NULLCHAR,    NULLCHAR,
  52.     "interface",    dointerface,    4,
  53.         "netrom interface <interface> <alias> <quality>",    NULLCHAR,
  54.     "irtt",            donrirtt,        0,    NULLCHAR,    NULLCHAR,
  55.     "kick",            donrkick,        0,    NULLCHAR,    NULLCHAR,
  56.     "nodefilter",    donodefilter,    0,    NULLCHAR,    NULLCHAR,
  57.     "nodetimer",    donodetimer,    0,    NULLCHAR,    NULLCHAR,
  58.     "obsotimer",    doobsotimer,    0,    NULLCHAR,    NULLCHAR,
  59.     "qlimit",    donrqlimit,    0,    NULLCHAR,    NULLCHAR,
  60.     "reset",    donrreset,    2,    "netrom reset <&nrcb>",    NULLCHAR,
  61.     "retries",    donrretries,0,    NULLCHAR,    NULLCHAR,
  62.     "route",    donrroute,    0,    NULLCHAR,    NULLCHAR,
  63.     "status",    donrstatus,    0,    NULLCHAR,    NULLCHAR,
  64.     "ttl",        donrttl,    0,    NULLCHAR,    NULLCHAR,
  65.     "verbose",    donrverbose,0,    NULLCHAR,    NULLCHAR,
  66.     "window",    donrwindow,    0,    NULLCHAR,    NULLCHAR,
  67.     NULLCHAR,    NULLFP,        0,
  68.         "netrom subcommands: acktime bcnodes connect choketime interface irtt kick\n                    nodetimer nodefilter obsotimer qlimit reset retries route\n                    status ttl verbose window",
  69.         NULLCHAR
  70. } ;
  71.  
  72. static struct timer nodetimer ;    /* timer for nodes broadcasts */
  73. static struct timer obsotimer ;    /* timer for aging routes */
  74.  
  75. /* Command multiplexer */
  76. donetrom(argc,argv)
  77. int argc ;
  78. char *argv[] ;
  79. {
  80.     return subcmd(nrcmds,argc,argv) ;
  81. }
  82.  
  83. static int dorouteadd(), doroutedrop(), doroutedump(), dorouteinfo() ;
  84.  
  85. static struct cmds routecmds[] = {
  86.     "add",    dorouteadd,    6,
  87.         "netrom route add <alias> <destination> <interface> <quality> <neighbor>",
  88.         "add failed",
  89.     "drop",    doroutedrop, 4,
  90.         "netrom route drop <destination> <neighbor> <interface>",
  91.         "drop failed",
  92.     "info", dorouteinfo, 2,
  93.         "netrom route info <destination>", NULLCHAR,
  94.     NULLCHAR,    NULLFP,    0,
  95.         "netrom route subcommands: add drop info",
  96.         NULLCHAR
  97. } ;
  98.  
  99. /* Route command multiplexer */
  100. static
  101. donrroute(argc, argv)
  102. int argc ;
  103. char *argv[] ;
  104. {
  105.     if (argc < 2) {
  106.         doroutedump() ;
  107.         return 0 ;
  108.     }
  109.     return subcmd(routecmds,argc,argv) ;
  110. }
  111.  
  112. /* Dump a list of known routes */
  113. static
  114. doroutedump()
  115. {
  116.     register struct nrroute_tab *rp ;
  117.     register int i, column ;
  118.     char buf[16] ;
  119.     char *cp ;
  120.     
  121.     column = 1 ;
  122.     
  123.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  124.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rp->next) {
  125.             strcpy(buf,rp->alias) ;
  126.             /* remove trailing spaces */
  127.             if ((cp = index(buf,' ')) == NULLCHAR)
  128.                 cp = &buf[strlen(buf)] ;
  129.             if (cp != buf)        /* don't include colon for null alias */
  130.                 *cp++ = ':' ;
  131.             pax25(cp,&rp->call) ;
  132.             printf("%-16s  ",buf) ;
  133.             if (column++ == 4) {
  134.                 printf("\n") ;
  135.                 column = 1 ;
  136.             }
  137.         }
  138.  
  139.     if (column != 1)
  140.         printf("\n") ;
  141.         
  142.     return 0 ;
  143. }
  144.  
  145. /* print detailed information on an individual route */
  146. dorouteinfo(argc,argv)
  147. int argc ;
  148. char *argv[] ;
  149. {
  150.     register struct nrroute_tab *rp ;
  151.     register struct nr_bind *bp ;
  152.     register struct nrnbr_tab *np ;
  153.     struct ax25_addr dest ;
  154.     char neighbor[60] ;
  155.  
  156.     if (setcall(&dest,argv[1]) == -1) {
  157.         printf ("bad destination name\n") ;
  158.         return -1 ;
  159.     }
  160.         
  161.     if ((rp = find_nrroute(&dest)) == NULLNRRTAB) {
  162.         printf("no such route\n") ;
  163.         return -1 ;
  164.     }
  165.  
  166.     for (bp = rp->routes ; bp != NULLNRBIND ; bp = bp->next) {
  167.         np = bp->via ;
  168.         psax25(neighbor,np->call) ;
  169.         printf("%1s %3d  %3d  %-8s  %s\n",
  170.                 (bp->flags & NRB_PERMANENT ? "P" :
  171.                  bp->flags & NRB_RECORDED ? "R" : " "),
  172.                 bp->quality,bp->obsocnt,
  173.                 nrifaces[np->interface].interface->name,
  174.                 neighbor) ;
  175.     }
  176.     return 0 ;
  177. }
  178.         
  179. /* convert a null-terminated alias name to a blank-filled, upcased */
  180. /* version.  Return -1 on failure. */
  181. static int
  182. putalias(to,from,complain)
  183. register char *to, *from ;
  184. int complain ;
  185. {
  186.     int len, i ;
  187.     
  188.     if ((len = strlen(from)) > ALEN) {
  189.         if (complain)
  190.             printf ("alias too long - six characters max\n") ;
  191.         return -1 ;
  192.     }
  193.     
  194.     for (i = 0 ; i < ALEN ; i++) {
  195.         if (i < len) {
  196.             if (islower(*from))
  197.                 *to++ = toupper(*from++) ;
  198.             else
  199.                 *to++ = *from++ ;
  200.         }
  201.         else
  202.             *to++ = ' ' ;
  203.     }
  204.             
  205.     *to = '\0' ;
  206.     return 0 ;
  207. }
  208.  
  209. /* Add a route */
  210. dorouteadd(argc, argv)
  211. int argc ;
  212. char *argv[] ;
  213. {
  214.     char alias[7] ;
  215.     struct ax25_addr dest ;
  216.     unsigned quality ;
  217.     char neighbor[AXALEN * 3] ;
  218.     register int i ;
  219.     int naddr ;
  220.  
  221.     /* format alias (putalias prints error message if necessary) */
  222.     if (putalias(alias,argv[1],1) == -1)
  223.         return -1 ;
  224.  
  225.     /* format destination callsign */
  226.     if (setcall(&dest,argv[2]) == -1) {
  227.         printf("bad destination callsign\n") ;
  228.         return -1 ;
  229.     }
  230.  
  231.     /* find interface */
  232.     for (i = 0 ; i < nr_numiface ; i++)
  233.         if (!strcmp(nrifaces[i].interface->name,argv[3]))
  234.             break ;
  235.     if (i == nr_numiface) {
  236.         printf("Interface \"%s\" not found\n",argv[3]) ;
  237.         return -1 ;
  238.     }
  239.     
  240.     /* get and check quality value */
  241.     if ((quality = atoi(argv[4])) > 255) {
  242.         printf("maximum route quality is 255\n") ;
  243.         return -1 ;
  244.     }
  245.  
  246.     /* make sure no more than 2 digis */
  247.     naddr = argc - 5 ;
  248.     if (naddr > 3) {
  249.         printf("no more than 2 digipeaters for a net/rom neighbor\n") ;
  250.         return -1 ;
  251.     }
  252.     
  253.     /* format neighbor address string */
  254.     setpath(neighbor,&argv[5],naddr) ;
  255.  
  256.     return nr_routeadd(alias,&dest,i,quality,neighbor,1,0) ;
  257. }
  258.  
  259.  
  260. /* drop a route */
  261. static
  262. doroutedrop(argc,argv)
  263. int argc ;
  264. char *argv[] ;
  265. {
  266.     struct ax25_addr dest, neighbor ;
  267.     register int i ;
  268.  
  269.     /* format destination and neighbor callsigns */
  270.     if (setcall(&dest,argv[1]) == -1) {
  271.         printf("bad destination callsign\n") ;
  272.         return -1 ;
  273.     }
  274.     if (setcall(&neighbor,argv[2]) == -1) {
  275.         printf("bad neighbor callsign\n") ;
  276.         return -1 ;
  277.     }
  278.  
  279.     /* find interface */
  280.     for (i = 0 ; i < nr_numiface ; i++)
  281.         if (!strcmp(nrifaces[i].interface->name,argv[3]))
  282.             break ;
  283.     if (i == nr_numiface) {
  284.         printf("Interface \"%s\" not found\n",argv[3]) ;
  285.         return -1 ;
  286.     }
  287.  
  288.     return nr_routedrop(&dest,&neighbor,i) ;
  289. }
  290.     
  291.     
  292. /* make an interface available to net/rom */
  293. int
  294. dointerface(argc,argv)
  295. int argc ;
  296. char *argv[] ;
  297. {
  298.     register char *sp, *dp ;
  299.     int i, len ;
  300.     register struct interface *ifp ;
  301.     extern struct interface *ifaces ;
  302.  
  303.     if (nr_interface == NULLIF) {
  304.         printf("Attach netrom interface first\n") ;
  305.         return 1 ;
  306.     }
  307.     
  308.     if (nr_numiface >= NRNUMIFACE) {
  309.         printf("Only %d net/rom interfaces available\n",NRNUMIFACE) ;
  310.         return 1 ;
  311.     }
  312.     
  313.     for(ifp=ifaces;ifp != NULLIF;ifp = ifp->next){
  314.         if(strcmp(argv[1],ifp->name) == 0)
  315.             break;
  316.     }
  317.     if(ifp == NULLIF){
  318.         printf("Interface \"%s\" unknown\n",argv[1]);
  319.         return 1;
  320.     }
  321.     for (i = 0 ; i < nr_numiface ; i++)
  322.         if (nrifaces[i].interface == ifp) {
  323.             printf("Interface \"%s\" is already registered\n",argv[1]) ;
  324.             return 1 ;
  325.         }
  326.         
  327.     nrifaces[nr_numiface].interface = ifp ;
  328.  
  329.     if (putalias(nrifaces[nr_numiface].alias,argv[2],1) == -1)
  330.         return 1 ;
  331.         
  332.     if ((nrifaces[nr_numiface].quality = atoi(argv[3])) > 255) {
  333.         printf("Quality cannot be greater than 255\n") ;
  334.         return 1 ;
  335.     }
  336.         
  337.     nr_numiface++ ;            /* accept this interface */
  338.     return 0 ;
  339. }
  340.  
  341. /* Broadcast nodes list on named interface. */
  342.  
  343. int
  344. dobcnodes(argc,argv)
  345. int argc ;
  346. char *argv[] ;
  347. {
  348.     register int i ;
  349.     for (i = 0 ; i < nr_numiface ; i++)
  350.         if (!strcmp(nrifaces[i].interface->name,argv[1]))
  351.             break ;
  352.     if (i == nr_numiface) {
  353.         printf("Interface \"%s\" not found\n",argv[1]) ;
  354.         return 1 ;
  355.     }
  356.         
  357.     nr_bcnodes(i) ;
  358. }
  359.  
  360. #define TICKSPERSEC    (1000L / MSPTICK)    /* Ticks per second */
  361.  
  362. /* Set outbound node broadcast interval */
  363. static int
  364. donodetimer(argc,argv)
  365. int argc;
  366. char *argv[];
  367. {
  368.     int donodetick();
  369.  
  370.     if(argc < 2){
  371.         printf("%lu/%lu\n",
  372.                 (nodetimer.start - nodetimer.count)/TICKSPERSEC,
  373.                 nodetimer.start/TICKSPERSEC);
  374.         return 0;
  375.     }
  376.     stop_timer(&nodetimer) ;    /* in case it's already running */
  377.     nodetimer.func = (void (*)())donodetick;/* what to call on timeout */
  378.     nodetimer.arg = NULLCHAR;        /* dummy value */
  379.     nodetimer.start = atol(argv[1])*TICKSPERSEC;    /* set timer duration */
  380.     start_timer(&nodetimer);        /* and fire it up */
  381.     return 0;
  382. }
  383.  
  384. static int
  385. donodetick()
  386. {
  387.     register int i ;
  388.  
  389.     for (i = 0 ; i < nr_numiface ; i++)
  390.         nr_bcnodes(i) ;
  391.  
  392.     /* Restart timer */
  393.     start_timer(&nodetimer) ;
  394. }
  395.  
  396. /* Set timer for aging routes */
  397. static int
  398. doobsotimer(argc,argv)
  399. int argc;
  400. char *argv[];
  401. {
  402.     extern int doobsotick();
  403.  
  404.     if(argc < 2){
  405.         printf("%lu/%lu\n",(obsotimer.start - obsotimer.count)/TICKSPERSEC,
  406.         obsotimer.start/TICKSPERSEC);
  407.         return 0;
  408.     }
  409.     stop_timer(&obsotimer) ;    /* just in case it's already running */
  410.     obsotimer.func = (void (*)())doobsotick;/* what to call on timeout */
  411.     obsotimer.arg = NULLCHAR;        /* dummy value */
  412.     obsotimer.start = atol(argv[1])*TICKSPERSEC;    /* set timer duration */
  413.     start_timer(&obsotimer);        /* and fire it up */
  414.     return 0;
  415. }
  416.  
  417.  
  418. /* Go through the routing table, reducing the obsolescence count of
  419.  * non-permanent routes, and purging them if the count reaches 0
  420.  */
  421. static int
  422. doobsotick()
  423. {
  424.     register struct nrnbr_tab *np ;
  425.     register struct nrroute_tab *rp, *rpnext ;
  426.     register struct nr_bind *bp, *bpnext ;
  427.     struct ax25_addr neighbor ;
  428.     int i ;
  429.  
  430.     for (i = 0 ; i < NRNUMCHAINS ; i++) {
  431.         for (rp = nrroute_tab[i] ; rp != NULLNRRTAB ; rp = rpnext) {
  432.             rpnext = rp->next ;     /* save in case we free this route */
  433.             for (bp = rp->routes ; bp != NULLNRBIND ; bp = bpnext) {
  434.                 bpnext = bp->next ;    /* in case we free this binding */
  435.                 if (bp->flags & NRB_PERMANENT)    /* don't age these */
  436.                     continue ;
  437.                 if (--bp->obsocnt == 0) {        /* time's up! */
  438.                     if (bp->next != NULLNRBIND)
  439.                         bp->next->prev = bp->prev ;
  440.                     if (bp->prev != NULLNRBIND)
  441.                         bp->prev->next = bp->next ;
  442.                     else
  443.                         rp->routes = bp->next ;
  444.                     rp->num_routes-- ;            /* one less binding */
  445.                     np = bp->via ;                /* find the neighbor */
  446.                     free(bp) ;                    /* now we can free the bind */
  447.                     /* Check to see if we can free the neighbor */
  448.                     if (--np->refcnt == 0) {
  449.                         if (np->next != NULLNTAB)
  450.                             np->next->prev = np->prev ;
  451.                         if (np->prev != NULLNTAB)
  452.                             np->prev->next = np->next ;
  453.                         else {
  454.                             memcpy(neighbor.call,np->call,ALEN) ;
  455.                             neighbor.ssid = np->call[ALEN] ;
  456.                             nrnbr_tab[nrhash(&neighbor)] = np->next ;
  457.                         }
  458.                         free(np) ;    /* free the storage */
  459.                     }
  460.                 }
  461.             }
  462.             if (rp->num_routes == 0) {        /* did we free them all? */
  463.                 if (rp->next != NULLNRRTAB)
  464.                     rp->next->prev = rp->prev ;
  465.                 if (rp->prev != NULLNRRTAB)
  466.                     rp->prev->next = rp->next ;
  467.                 else
  468.                     nrroute_tab[i] = rp->next ;
  469.  
  470.                 free(rp) ;
  471.             }
  472.         }
  473.     }
  474.  
  475.     start_timer(&obsotimer) ;
  476. }
  477.  
  478.  
  479. static int donfadd(), donfdrop(), donfmode() ;
  480.  
  481. static struct cmds nfcmds[] = {
  482.     "add",    donfadd,    3,
  483.         "netrom nodefilter add <neighbor> <interface>",
  484.         "add failed",
  485.     "drop",    donfdrop,    3,
  486.         "netrom nodefilter drop <neighbor> <interface>",
  487.         "drop failed",
  488.     "mode",    donfmode,    0,    NULLCHAR,    NULLCHAR,
  489.     NULLCHAR,    NULLFP,    0,
  490.         "nodefilter subcommands: add drop mode",
  491.         NULLCHAR
  492. } ;
  493.  
  494. /* nodefilter command multiplexer */
  495. static
  496. donodefilter(argc,argv)
  497. int argc ;
  498. char *argv[] ;
  499. {
  500.     if (argc < 2) {
  501.         donfdump() ;
  502.         return 0 ;
  503.     }
  504.     return subcmd(nfcmds,argc,argv) ;
  505. }
  506.  
  507. /* display a list of <callsign,interface> pairs from the filter
  508.  * list.
  509.  */
  510. static
  511. donfdump()
  512. {
  513.     int i, column = 1 ;
  514.     struct nrnf_tab *fp ;
  515.     char buf[16] ;
  516.  
  517.     for (i = 0 ; i < NRNUMCHAINS ; i++)
  518.         for (fp = nrnf_tab[i] ; fp != NULLNRNFTAB ; fp = fp->next) {
  519.             pax25(buf,&fp->neighbor) ;
  520.             printf("%-7s %-8s  ",
  521.                     buf,nrifaces[fp->interface].interface->name) ;
  522.             if (column++ == 4) {
  523.                 printf("\n") ;
  524.                 column = 1 ;
  525.             }
  526.         }
  527.  
  528.     if (column != 1)
  529.         printf("\n") ;
  530.  
  531.     return 0 ;
  532. }
  533.  
  534. /* add an entry to the filter table */
  535. static
  536. donfadd(argc,argv)
  537. int argc ;
  538. char *argv[] ;
  539. {
  540.     struct ax25_addr neighbor ;
  541.     register int i ;
  542.  
  543.     /* format callsign */
  544.     if (setcall(&neighbor,argv[1]) == -1) {
  545.         printf("bad neighbor callsign\n") ;
  546.         return -1 ;
  547.     }
  548.  
  549.     /* find interface */
  550.     for (i = 0 ; i < nr_numiface ; i++)
  551.         if (!strcmp(nrifaces[i].interface->name,argv[2]))
  552.             break ;
  553.     if (i == nr_numiface) {
  554.         printf("Interface \"%s\" not found\n",argv[2]) ;
  555.         return -1 ;
  556.     }
  557.  
  558.     return nr_nfadd(&neighbor,i) ;
  559. }
  560.  
  561. /* drop an entry from the filter table */
  562. static
  563. donfdrop(argc,argv)
  564. int argc ;
  565. char *argv[] ;
  566. {
  567.     struct ax25_addr neighbor ;
  568.     register int i ;
  569.  
  570.     /* format neighbor callsign */
  571.     if (setcall(&neighbor,argv[1]) == -1) {
  572.         printf("bad neighbor callsign\n") ;
  573.         return -1 ;
  574.     }
  575.  
  576.     /* find interface */
  577.     for (i = 0 ; i < nr_numiface ; i++)
  578.         if (!strcmp(nrifaces[i].interface->name,argv[2]))
  579.             break ;
  580.     if (i == nr_numiface) {
  581.         printf("Interface \"%s\" not found\n",argv[2]) ;
  582.         return -1 ;
  583.     }
  584.  
  585.     return nr_nfdrop(&neighbor,i) ;
  586. }
  587.  
  588. /* nodefilter mode subcommand */
  589. static
  590. donfmode(argc,argv)
  591. int argc ;
  592. char *argv[] ;
  593. {
  594.     if (argc < 2) {
  595.         printf("filter mode is ") ;
  596.         switch (nr_nfmode) {
  597.             case NRNF_NOFILTER:
  598.                 printf("none\n") ;
  599.                 break ;
  600.             case NRNF_ACCEPT:
  601.                 printf("accept\n") ;
  602.                 break ;
  603.             case NRNF_REJECT:
  604.                 printf("reject\n") ;
  605.                 break ;
  606.             default:
  607.                 printf("some strange, unknown value\n") ;
  608.         }
  609.         return 0 ;
  610.     }
  611.     
  612.     switch (argv[1][0]) {
  613.         case 'n':
  614.         case 'N':
  615.             nr_nfmode = NRNF_NOFILTER ;
  616.             break ;
  617.         case 'a':
  618.         case 'A':
  619.             nr_nfmode = NRNF_ACCEPT ;
  620.             break ;
  621.         case 'r':
  622.         case 'R':
  623.             nr_nfmode = NRNF_REJECT ;
  624.             break ;
  625.         default:
  626.             printf("modes are: none accept reject\n") ;
  627.             return -1 ;
  628.     }
  629.  
  630.     return 0 ;
  631. }
  632.  
  633.  
  634. /* netrom network packet time-to-live initializer */
  635. static
  636. donrttl(argc, argv)
  637. int argc ;
  638. char *argv[] ;
  639. {
  640.     int val ;
  641.  
  642.     if (argc < 2) {
  643.         printf("%d\n", nr_ttl) ;
  644.         return 0 ;
  645.     }
  646.  
  647.     val = atoi(argv[1]) ;
  648.  
  649.     if (val < 0 || val > 255) {
  650.         printf("ttl must be between 0 and 255\n") ;
  651.         return 1 ;
  652.     }
  653.  
  654.     nr_ttl = val ;
  655.  
  656.     return 0 ;
  657. }
  658.  
  659. /* verbose route broadcast */
  660. static
  661. donrverbose(argc,argv)
  662. int argc ;
  663. char *argv[] ;
  664. {
  665.     if (argc < 2) {
  666.         printf("verbose is %s\n", nr_verbose ? "yes" : "no" ) ;
  667.         return 0 ;
  668.     }
  669.     
  670.     switch (argv[1][0]) {
  671.         case 'n':
  672.         case 'N':
  673.             nr_verbose = 0 ;
  674.             break ;
  675.         case 'y':
  676.         case 'Y':
  677.             nr_verbose = 1 ;
  678.             break ;
  679.         default:
  680.             printf("use: netrom verbose [yes|no]\n") ;
  681.             return -1 ;
  682.     }
  683.  
  684.     return 0 ;
  685. }
  686.  
  687. /* Initiate a NET/ROM transport connection */
  688. int
  689. donrconnect(argc,argv)
  690. int argc ;
  691. char *argv[] ;
  692. {
  693.     struct ax25_addr node, *np ;
  694.     struct nr4cb *cb ;
  695.     struct session *s ;
  696.     char alias[7] ;
  697.     int (*nr4_parse)();
  698.  
  699.     /* See if the requested destination could be an alias, and */
  700.     /* find and use it if it is.  Otherwise assume it is an ax.25 */
  701.     /* address. */
  702.     
  703.     if (putalias(alias,argv[1],0) != -1 &&
  704.         (np = find_nralias(alias)) != NULLAXADDR)
  705.           node = *np ;
  706.     else
  707.         setcall(&node,argv[1]) ;    /* parse ax25 callsign */
  708.  
  709.     /* Get a session descriptor */
  710.  
  711.     if ((s = newsession()) == NULLSESSION) {
  712.         printf("Too many sessions\n") ;
  713.         return 1 ;
  714.     }
  715.  
  716.     if((s->name = malloc((unsigned)strlen(argv[1])+1)) != NULLCHAR)
  717.         strcpy(s->name,argv[1]);
  718.     s->type = NRSESSION ;
  719.      s->parse = nr4_parse ; 
  720.     current = s;
  721.  
  722.     s->cb.nr4_cb = open_nr4(&node,&mycall,nr4_rx,nr4_tx,nr4_state,(char *)s) ;
  723.     go() ;
  724.     return 0 ;
  725. }
  726.  
  727. /* Display changes in NET/ROM state */
  728. void
  729. nr4_state(cb,old,new)
  730. struct nr4cb *cb ;
  731. int old,new;
  732. {
  733.     struct session *s;
  734.  
  735.     s = (struct session *)cb->puser;
  736.  
  737.     if(current != NULLSESSION && current->type == NRSESSION && current == s){
  738.         printf("%s",Nr4states[new]);
  739.         if(new == NR4STDISC) {
  740.             printf(" (%s)\n", Nr4reasons[cb->dreason]) ;
  741.             cmdmode();
  742.         } else
  743.             printf("\n") ;
  744.         fflush(stdout);
  745.     }
  746.     if(new == NR4STDISC){
  747.         cb->puser = NULLCHAR;
  748.         freesession(s);
  749.     }
  750. }
  751.  
  752. /* Handle typed characters on a NET/ROM connection */
  753. void
  754. nr4_parse(buf,cnt)
  755. char *buf;
  756. int16 cnt;
  757. {
  758.     struct mbuf *bp;
  759.     register char *cp;
  760.     int16 size, i ;
  761.     char c;
  762.  
  763.     if(current == NULLSESSION || current->type != NRSESSION)
  764.         return;    /* "can't happen" */
  765.  
  766.     /* If recording is on, record outgoing stuff too */
  767.     if(current->record != NULLFILE)
  768.         fwrite(buf,1,cnt,current->record);
  769.  
  770.     /* Parse it out, splitting at transport frame boundaries */
  771.     
  772.     while (cnt != 0) {
  773. #ifdef NRDEBUG
  774.         printf("Once around the parse loop - cnt = %d\n", cnt) ;
  775. #endif
  776.         size = min(cnt, NR4MAXINFO) ;
  777.         if ((bp = alloc_mbuf(size)) == NULLBUF)
  778.             break ;
  779.         /* Copy keyboard buffer to output, stripping line feeds */
  780.         cp = bp->data ;
  781.         for (i = 0 ; i < size ; i++){
  782.             c = *buf++;
  783.             if(c != '\n'){
  784.                 *cp++ = c;
  785.                 bp->cnt++;
  786.             }
  787.         }
  788.         cnt -= size ;
  789.         send_nr4(current->cb.nr4_cb,bp);
  790.     }
  791. }
  792.  
  793. /* Handle new incoming terminal sessions
  794.  * This is the default state change upcall function, used when
  795.  * someone else connects to us
  796.  */
  797. void
  798. nr4_incom(cb,oldstate,newstate)
  799. struct nr4cb *cb ;
  800. int oldstate ;
  801. int newstate ;
  802. {
  803.     void nr4_session() ;
  804.  
  805.     if (newstate != NR4STCON)        /* why are you bothering us? */
  806.         return ;                    /* (shouldn't happen) */
  807.         
  808.     if (ax25mbox)
  809.         mbx_nr4incom(cb) ;
  810.     else
  811.         nr4_session(cb) ;
  812.     return ;
  813.  
  814. }
  815.  
  816. /* This function sets up a NET/ROM chat session */
  817. void
  818. nr4_session(cb)
  819. struct nr4cb *cb ;
  820. {
  821.     struct session *s;
  822.     char remote[10];
  823.     int (*nr4_parse)();
  824.  
  825.     pax25(remote,&cb->user);
  826.     if((s = newsession()) == NULLSESSION){
  827.         /* Out of sessions */
  828.         disc_nr4(cb);
  829.         return;
  830.     }
  831.     s->type = NRSESSION ;
  832.     s->name = malloc((int16)strlen(remote)+1);
  833.     s->cb.nr4_cb = cb ;
  834.      s->parse = nr4_parse; 
  835.     strcpy(s->name,remote);
  836.     cb->r_upcall = nr4_rx;
  837.     cb->s_upcall = nr4_state;
  838.     cb->t_upcall = nr4_tx;
  839.     cb->puser = (char *)s;
  840. #if    (defined(MAC) || defined(AMIGA))
  841.     printf("\007Incoming NET/ROM session %lu from %s\n",s - sessions,remote);
  842. #else
  843.     printf("\007Incoming NET/ROM session %u from %s\n",s - sessions,remote);
  844. #endif
  845.     fflush(stdout);
  846. }
  847.  
  848. /* Handle incoming terminal traffic */
  849. void
  850. nr4_rx(cb,cnt)
  851. struct nr4cb *cb ;
  852. int16 cnt;
  853. {
  854.     register struct mbuf *bp;
  855.     char c;
  856.  
  857.     /* Hold output if we're not the current session */
  858.     if(mode != CONV_MODE || current == NULLSESSION
  859.      || current->type != NRSESSION || current->cb.nr4_cb != cb)
  860.         return;
  861.  
  862.     if((bp = recv_nr4(cb,cnt)) == NULLBUF)
  863.         return;
  864.  
  865.     /* Display received characters, translating CR's to CR/LF */
  866.     while(bp != NULLBUF){
  867.         while(bp->cnt-- != 0){
  868.             c = *bp->data++;
  869.             if(c == '\r')
  870.                 c = '\n';
  871.             putchar(c);
  872.             if(current->record){
  873. #ifndef UNIX
  874. #ifndef MAC
  875.                 if(c == '\n')
  876.                     fputc('\r',current->record);
  877. #endif
  878. #endif
  879.                 fputc(c,current->record);
  880.             }
  881.         }
  882.         bp = free_mbuf(bp);
  883.     }
  884.     if(current->record)
  885.         fflush(current->record);
  886.     fflush(stdout);
  887. }
  888.  
  889. /* Handle transmit upcalls. Used only for file uploading */
  890. void
  891. nr4_tx(cb,cnt)
  892. struct nr4cb *cb ;
  893. int16 cnt;
  894. {
  895.     register char *cp;
  896.     struct session *s;
  897.     register struct mbuf *bp;
  898.     int16 size;
  899.     int c;
  900.  
  901.     if((s = (struct session *)cb->puser) == NULLSESSION
  902.      || s->upload == NULLFILE)
  903.         return;
  904.     while(cnt != 0){
  905.         size = min(cnt,NR4MAXINFO);
  906.         if((bp = alloc_mbuf(size)) == NULLBUF)
  907.             break;
  908.         cp = bp->data;
  909.  
  910.         /* Now send data characters, translating between local
  911.          * keyboard end-of-line sequences and the (unwritten)
  912.          * AX.25 convention, which is carriage-return only
  913.          */
  914.          
  915.         while(bp->cnt < size){
  916.             if((c = getc(s->upload)) == EOF)
  917.                 break;
  918. #ifdef    MSDOS
  919.             /* MS-DOS gives cr-lf */
  920.             if(c == '\n')
  921.                 continue;
  922. #endif
  923. #if    (defined(UNIX) || defined(MAC) || defined(AMIGA))
  924.             /* These give lf only */
  925.             if(c == '\n')
  926.                 c = '\r';
  927. #endif
  928.             *cp++ = c;
  929.             bp->cnt++;
  930.         }    
  931.         cnt -= bp->cnt;
  932.         send_nr4(cb,bp);
  933.     }
  934.     if(cnt != 0){
  935.         /* Error or end-of-file */
  936.         fclose(s->upload);
  937.         s->upload = NULLFILE;
  938.         free(s->ufile);
  939.         s->ufile = NULLCHAR;
  940.     }
  941. }
  942.  
  943. /* Reset a net/rom connection abruptly */
  944.  
  945. static int
  946. donrreset(argc,argv)
  947. int argc;
  948. char *argv[];
  949. {
  950.     struct nr4cb *cb ;
  951.     extern char notval[];
  952.  
  953.     cb = (struct nr4cb *)htol(argv[1]);
  954.     if(!nr4valcb(cb)){
  955.         printf(notval);
  956.         return 1;
  957.     }
  958.     reset_nr4(cb);
  959.     return 0;
  960. }
  961.  
  962. /* Force retransmission on a net/rom connection */
  963.  
  964. static int
  965. donrkick(argc,argv)
  966. int argc;
  967. char *argv[];
  968. {
  969.     struct nr4cb *cb ;
  970.     extern char notval[];
  971.  
  972.     cb = (struct nr4cb *)htol(argv[1]);
  973.  
  974.     if (kick_nr4(cb) == -1) {
  975.         printf(notval);
  976.         return 1;
  977.     } else
  978.         return 0;
  979. }
  980.  
  981. /* netrom transport ACK delay timer */
  982.  
  983. static
  984. donracktime(argc, argv)
  985. int argc ;
  986. char *argv[] ;
  987. {
  988.     long val ;
  989.  
  990.     if (argc < 2) {
  991.         printf("%lu\n", Nr4acktime) ;
  992.         return 0 ;
  993.     }
  994.  
  995.     val = atol(argv[1]) ;
  996.  
  997.     Nr4acktime = val ;
  998.  
  999.     return 0 ;
  1000. }
  1001.  
  1002. /* netrom transport choke timeout */
  1003.  
  1004. static
  1005. donrchoketime(argc, argv)
  1006. int argc ;
  1007. char *argv[] ;
  1008. {
  1009.     long val ;
  1010.  
  1011.     if (argc < 2) {
  1012.         printf("%lu\n", Nr4choketime) ;
  1013.         return 0 ;
  1014.     }
  1015.  
  1016.     val = atol(argv[1]) ;
  1017.  
  1018.     Nr4choketime = val ;
  1019.  
  1020.     return 0 ;
  1021. }
  1022.  
  1023. /* netrom transport initial round trip time */
  1024.  
  1025. static
  1026. donrirtt(argc, argv)
  1027. int argc ;
  1028. char *argv[] ;
  1029. {
  1030.     long val ;
  1031.  
  1032.     if (argc < 2) {
  1033.         printf("%lu\n", Nr4irtt) ;
  1034.         return 0 ;
  1035.     }
  1036.  
  1037.     val = atol(argv[1]) ;
  1038.  
  1039.     Nr4irtt = val ;
  1040.  
  1041.     return 0 ;
  1042. }
  1043.  
  1044. /* netrom transport receive queue length limit.  This is the */
  1045. /* threshhold at which we will CHOKE the sender. */
  1046.  
  1047. static
  1048. donrqlimit(argc, argv)
  1049. int argc ;
  1050. char *argv[] ;
  1051. {
  1052.     unsigned val ;
  1053.  
  1054.     if (argc < 2) {
  1055.         printf("%u\n", Nr4qlimit) ;
  1056.         return 0 ;
  1057.     }
  1058.  
  1059.     val = atoi(argv[1]) ;
  1060.  
  1061.     if (val == 0) {
  1062.         printf("You cannot set the queue limit to 0\n") ;
  1063.         return 1 ;
  1064.     }
  1065.     
  1066.     Nr4qlimit = val ;
  1067.  
  1068.     return 0 ;
  1069. }
  1070.  
  1071. /* netrom transport maximum window.  This is the largest send and */
  1072. /* receive window we may negotiate */
  1073.  
  1074. static
  1075. donrwindow(argc, argv)
  1076. int argc ;
  1077. char *argv[] ;
  1078. {
  1079.     unsigned val ;
  1080.  
  1081.     if (argc < 2) {
  1082.         printf("%u\n", Nr4window) ;
  1083.         return 0 ;
  1084.     }
  1085.  
  1086.     val = atoi(argv[1]) ;
  1087.  
  1088.     if (val == 0 || val > NR4MAXWIN) {
  1089.         printf("Illegal NET/ROM window size.  Range is [1,%d]\n",
  1090.                NR4MAXWIN) ;
  1091.         return 1 ;
  1092.     }
  1093.     
  1094.     Nr4window = val ;
  1095.  
  1096.     return 0 ;
  1097. }
  1098.  
  1099. /* netrom transport maximum retries.  This is used in connect and */
  1100. /* disconnect attempts; I haven't decided what to do about actual */
  1101. /* data retries yet. */
  1102.  
  1103. static
  1104. donrretries(argc, argv)
  1105. int argc ;
  1106. char *argv[] ;
  1107. {
  1108.     unsigned val ;
  1109.  
  1110.     if (argc < 2) {
  1111.         printf("%u\n", Nr4retries) ;
  1112.         return 0 ;
  1113.     }
  1114.  
  1115.     val = atoi(argv[1]) ;
  1116.  
  1117.     if (val == 0) {
  1118.         printf("Impatient, aren't we?  Zero retries not possible\n") ;
  1119.         return 1 ;
  1120.     }
  1121.     
  1122.     Nr4retries = val ;
  1123.  
  1124.     return 0 ;
  1125. }
  1126.  
  1127. /* Display the status of NET/ROM connections */
  1128.  
  1129. static
  1130. donrstatus(argc, argv)
  1131. int argc ;
  1132. char *argv[] ;
  1133. {
  1134.     int i ;
  1135.     struct nr4cb *cb ;
  1136.     char luser[10], ruser[10], node[10] ;
  1137.     extern char notval[] ;
  1138.     static void donrdump() ;
  1139.     
  1140.     if (argc < 2) {
  1141.         printf("     &CB Snd-W Snd-Q Rcv-Q     LUser      RUser @Node     State\n");
  1142.         for (i = 0 ; i < NR4MAXCIRC ; i++) {
  1143.             if ((cb = Nr4circuits[i].ccb) == NULLNR4CB)
  1144.                 continue ;
  1145.             pax25(luser,&cb->luser) ;
  1146.             pax25(ruser,&cb->user) ;
  1147.             pax25(node,&cb->node) ;
  1148.             printf("%8lx   %3d %5d %5d %9s  %9s %-9s %s\n",
  1149.                    (long)cb, cb->nbuffered, len_q(cb->txq),
  1150.                    len_mbuf(cb->rxq), luser, ruser, node,
  1151.                    Nr4states[cb->state]) ;
  1152.         }
  1153.         return 0 ;
  1154.     }
  1155.  
  1156.     cb = (struct nr4cb *)htol(argv[1]) ;
  1157.     if (!nr4valcb(cb)) {
  1158.         printf(notval) ;
  1159.         return 1 ;
  1160.     }
  1161.  
  1162.     donrdump(cb) ;
  1163.     return 0 ;
  1164. }
  1165.  
  1166. /* Dump one control block */
  1167.  
  1168. void
  1169. donrdump(cb)
  1170. struct nr4cb *cb ;
  1171. {
  1172.     int i ;
  1173.     char luser[10], ruser[10], node[10] ;
  1174.     unsigned seq ;
  1175.     struct nr4txbuf *b ;
  1176.     struct timer *t ;
  1177.  
  1178.     pax25(luser,&cb->luser) ;
  1179.     pax25(ruser,&cb->user) ;
  1180.     pax25(node, &cb->node) ;
  1181.  
  1182.     printf("Local: %s %d/%d Remote: %s @ %s %d/%d State: %s\n",
  1183.            luser, cb->mynum, cb->myid, ruser, node,
  1184.            cb->yournum, cb->yourid, Nr4states[cb->state]) ;
  1185.  
  1186.     printf("Window: %-5u Rxpect: %-5u RxNext: %-5u RxQ: %-5d %s\n",
  1187.            cb->window, uchar(cb->rxpected), uchar(cb->rxpastwin),
  1188.            len_mbuf(cb->rxq), cb->qfull ? "RxCHOKED" : "") ;
  1189.  
  1190.     printf(" Unack: %-5u Txpect: %-5u TxNext: %-5u TxQ: %-5d %s\n",
  1191.            cb->nbuffered, uchar(cb->ackxpected), uchar(cb->nextosend),
  1192.            len_q(cb->txq), cb->choked ? "TxCHOKED" : "") ;
  1193.  
  1194.     printf("TACK: ") ;
  1195.     if (run_timer(&cb->tack))
  1196.         printf("%lu", (cb->tack.start - cb->tack.count) * MSPTICK) ;
  1197.     else
  1198.         printf("stop") ;
  1199.     printf("/%lu ms; ", cb->tack.start * MSPTICK) ;
  1200.  
  1201.     printf("TChoke: ") ;
  1202.     if (run_timer(&cb->tchoke))
  1203.         printf("%lu", (cb->tchoke.start - cb->tchoke.count) * MSPTICK) ;
  1204.     else
  1205.         printf("stop") ;
  1206.     printf("/%lu ms; ", cb->tchoke.start * MSPTICK) ;
  1207.  
  1208.     printf("TCD: ") ;
  1209.     if (run_timer(&cb->tcd))
  1210.         printf("%lu", (cb->tcd.start - cb->tcd.count) * MSPTICK) ;
  1211.     else
  1212.         printf("stop") ;
  1213.     printf("/%lu ms", cb->tcd.start * MSPTICK) ;
  1214.  
  1215.     if (run_timer(&cb->tcd))
  1216.         printf("; Tries: %u\n", cb->cdtries) ;
  1217.     else
  1218.         printf("\n") ;
  1219.  
  1220.     printf("Backoff Level %u SRTT %ld ms Mean dev %ld ms\n",
  1221.            cb->blevel, cb->srtt, cb->mdev) ;
  1222.  
  1223.     /* If we are connected and the send window is open, display */
  1224.     /* the status of all the buffers and their timers */
  1225.     
  1226.     if (cb->state == NR4STCON && cb->nextosend != cb->ackxpected) {
  1227.  
  1228.         printf("TxBuffers:  Seq  Size  Tries  Timer\n") ;
  1229.  
  1230.         for (seq = cb->ackxpected ;
  1231.              nr4between(cb->ackxpected, seq, cb->nextosend) ;
  1232.              seq = (seq + 1) & NR4SEQMASK) {
  1233.  
  1234.             b = &cb->txbufs[seq % cb->window] ;
  1235.             t = &b->tretry ;
  1236.  
  1237.             printf("            %3u   %3d  %5d  %lu/%lu\n",
  1238.                    seq, len_mbuf(b->data), b->retries + 1,
  1239.                    (t->start - t->count) * MSPTICK, t->start * MSPTICK) ;
  1240.         }
  1241.  
  1242.     }
  1243.  
  1244. }
  1245.  
  1246.